package coalition;

import java.util.ArrayList;
import java.util.List;

import population.PopulationInterface;
import ccpv.NamedArrayList;


/*
 * This class is used to conveniently print coaltions
 */

public class CoalitionPrint {
	private final static int ALL_USED_FLAG = Integer.MAX_VALUE;

	public static String getCoalitionPrintString(List<int[]> ascriptives, ArrayList2D referenceList, PopulationInterface pop, int year)
	{
		int count = 1;
		String retString = "-----COALITION START-----\n";
		retString += "DATE: " + year + "\n";
		retString += "\n";

		// Looping through members of the coalition
		for (int i = 0; i < ascriptives.size(); i++)
		{
			// current group under consideration
			int[] currentMember = ascriptives.get(i);
			if (pop.getSectorPopulationSize(currentMember) != 0)
			{
				retString += "--GROUP " + (count) + "--\n";
				count++;
				if (currentMember.length != referenceList.size())
				{
					return "Error in printing: ascriptives size mismatch";
				}
				else
				{
					// Looping through currentMember to find out what each ascriptive is (ie Japanese)
					for (int j = 0; j < currentMember.length; j++)
					{
						// -1 indicates that the current ascriptive characteristic does not factor into 
						// the coalition decision
						if (currentMember[j] != -1)
						{
							NamedArrayList currentRef = referenceList.get(j);
							retString += "" + currentRef.getName() + ": " + currentRef.get(currentMember[j]) + "\n";
						}
						else
						{
							retString += "!!!!!!!!!!!!!!NEGATIVE ONE FOUND!!!!!!!!!!!!!!!! \n";
							NamedArrayList currentRef = referenceList.get(j);
							retString += "" + currentRef.getName() + ": " + "Any " + currentRef.getName() + "\n";
						}
					}
				}
				//spacing for the group
				retString += "  \n";
			}
		}

		retString += "-----COALITION END-----\n";
		return retString;
	}

	public static String getCoalitionPrintStringWithComplements(List<int[]> ascriptives, ArrayList2D referenceList, PopulationInterface pop, int year)
	{
		// used to identify group numbers
		int count = 1;
		String retString = "-----COALITION START-----\n";
		retString += "DATE: " + year + "\n";
		retString += "COALITION POWER: " + findCoalitionPower(ascriptives, pop) + "%\n";
		retString += "\n";

		// check for complements
		ArrayList<ArrayList<String>> complementChecked = complementCheck(ascriptives, referenceList);

		for (int i = 0; i < complementChecked.size(); i++)
		{
			retString += "Group " + (i+1) + "\n";
			ArrayList<String> group = complementChecked.get(i);
			//System.out.println("GROUP SIZE IS : " + group.size());
			for (int j = 0; j < group.size(); j++)
			{
				retString += referenceList.get(j).getName() + ": ";
				retString += group.get(j) + "\n";
			}
			retString += "\n";
		}

		retString += "-----COALITION END-----\n";
		return retString;
	}

	/*
	 * Returns a List<int[]> representing the new representation of the coalition.  The smallest
	 * List will always be returned, whether it is the original list or the complement. The symbols for
	 * complement will be -10 to -infinity.  -10 means the NOT referenceList.get(0).  -11 means NOT 
	 * referenceList.get(1).  -12 means NOT referenceList.get(2).  And so forth.
	 * 
	 * Since it is possible to have multiple ascriptives in a single complement, we need to alter the
	 * representation.  List<List<List<Int>>> is used now. 
	 * 
	 * Example:
	 * [[A][B]] This is a list of 2 groups, A and B
	 * [A] = [[1][2][-3, -4]] As one can see, the last member represents a complement.  It is 
	 * (NOT 3 and NOT 4).  
	 */
	
	private static ArrayList<ArrayList<String>> complementCheck(List<int[]> ascriptives, ArrayList2D referenceList)
	{
		System.out.println("THIS IS THE ASCRIPTIVES:");
		printAscriptiveList(ascriptives);
		
		// represented is the list of which ascriptive characteristics were found in the coalition.   
		ArrayList<ArrayList<Integer>> represented = new ArrayList<ArrayList<Integer>>();
		// the return list
		ArrayList<ArrayList<ArrayList<Integer>>> retIntVersion = new ArrayList<ArrayList<ArrayList<Integer>>>();
		// the string version of the ret list
		ArrayList<ArrayList<String>> retStringVersion = new ArrayList<ArrayList<String>>();

		// first setup the ret list by copying all information from ascriptives
		//ArrayList<ArrayList<ArrayList<Integer>>> ascCopy = new ArrayList<ArrayList<ArrayList<Integer>>>();
		for (int i = 0; i < ascriptives.size(); i++)
		{
			int[] currentGroup = ascriptives.get(i);
			ArrayList<ArrayList<Integer>> currentGroupList = new ArrayList<ArrayList<Integer>>();
			for (int j = 0; j < currentGroup.length; j++)
			{
				ArrayList<Integer> currentAsc = new ArrayList<Integer>(); 
				currentAsc.add(currentGroup[j]);
				currentGroupList.add(currentAsc);
			}
			
			retIntVersion.add(currentGroupList);
		}
		
		// Here we handle each category in the referenceList one at a time, replacing them
		// w/ complements or allUsed sets, if needed.
		for (int i = 0; i < referenceList.size(); i++)
		{
			NamedArrayList currentRefCat = referenceList.get(i);
			ArrayList<Integer> refGroup = new ArrayList<Integer>();
			
			// Create the set containing all represented groups.
			for (int j = 0; j < ascriptives.size(); j++)
			{
				int[] currentGroup = ascriptives.get(j);
				
				// register what is represented
				if (!refGroup.contains(currentGroup[i]))
				{
					if (currentGroup[i] == 11)
						System.out.println("11 detected at i = " + i);
					refGroup.add(currentGroup[i]);
				}
			}
			
			// use complement if complement is smaller.
			int compSize = currentRefCat.size() - refGroup.size();
			ArrayList<Integer> compSet = new ArrayList<Integer>();
			ArrayList<Integer> allUsedSet = new ArrayList<Integer>();
			allUsedSet.add(ALL_USED_FLAG);
			boolean complementUsed = false;
			boolean allUsed = false;
			if (compSize == 0)
				allUsed = true;
			if ((compSize < refGroup.size()) && (compSize != 0))
			{
				complementUsed = true;
				// create compset
				for (int j = 0; j < currentRefCat.size(); j++)
				{
					if (!refGroup.contains(j))
						compSet.add(findCompVersion(j));
				}
			}
			
			// replace groups with alternate representations if needed.  If complementUsed, replace
			// w/ compSet.  If allUsed, replace w/ allUsedSet.
			for (int j = 0; j < retIntVersion.size(); j++)
			{
				ArrayList<ArrayList<Integer>> currentAscCopyGroup = retIntVersion.get(j);
				if (complementUsed)
				{
					currentAscCopyGroup.set(i, compSet);
				}
				if (allUsed)
				{
					currentAscCopyGroup.set(i, allUsedSet);
				}
			}
			
		}
		
		retIntVersion = removeDuplicates(retIntVersion);
		
		// Create string version of ret list
		for (int i = 0; i < retIntVersion.size(); i++)
		{
			ArrayList<ArrayList<Integer>> currentGroup = retIntVersion.get(i);
			ArrayList<String> currentStringGroup = new ArrayList<String>();
			for (int j = 0; j < currentGroup.size(); j++)
			{
				ArrayList<Integer> currentAsc = currentGroup.get(j);
				// if all used
				if (currentAsc.get(0) == ALL_USED_FLAG)
				{
					currentStringGroup.add("Any");
				}
				// if comp
				else if (currentAsc.get(0) < 0)
				{
					String notString = "NOT (";
					for (int k = 0; k < currentAsc.size()-1; k++)
					{
						notString += (String)referenceList.get(j).get(findNormVersion(currentAsc.get(k))) + ", ";
					}
					notString += (String)referenceList.get(j).get(findNormVersion(currentAsc.get(currentAsc.size()-1))) + ")";
					currentStringGroup.add(notString);
				}
				// if normal
				else
				{
					System.out.println("this is the reflist size: " + referenceList.get(j).size());
					System.out.println("this is the currentAsc at 0: " + currentAsc.get(0));
					currentStringGroup.add((String)referenceList.get(j).get(currentAsc.get(0)));
				}
			}
			retStringVersion.add(currentStringGroup);
		}

		//System.out.println("THIS IS THE NEW FORM:");
		//printCoalition(retIntVersion);
		return retStringVersion;
	}
	
	// Returns the power of the coalition described by ascriptives as a percentage
	private static double findCoalitionPower(List<int[]> ascriptives, PopulationInterface pop)
	{
		double ret = 0;
		
		for (int i = 0; i<ascriptives.size(); i++)
		{
			ret += pop.getSectorModulatedPopulationSize(ascriptives.get(i));
		}
		System.out.println("this is the total: " + pop.getTotalModulatedSize());
		System.out.println("this is the coalition pwr: " + ret);
		ret = ((ret/pop.getTotalModulatedSize()) * 100);	
		
		return ret;
	}
	
	/*
	private static ArrayList<ArrayList<ArrayList<Integer>>> complementCheck(List<int[]> ascriptives, ArrayList2D referenceList)
	{
		System.out.println("THIS IS THE ASCRIPTIVES:");
		printAscriptiveList(ascriptives);
		
		// represented is the list of which ascriptive characteristics were found in the coalition.   
		ArrayList<ArrayList<Integer>> represented = new ArrayList<ArrayList<Integer>>();
		// the return list
		ArrayList<ArrayList<ArrayList<Integer>>> ret = new ArrayList<ArrayList<ArrayList<Integer>>>();

		// first setup the ret list by copying all information from ascriptives
		//ArrayList<ArrayList<ArrayList<Integer>>> ascCopy = new ArrayList<ArrayList<ArrayList<Integer>>>();
		for (int i = 0; i < ascriptives.size(); i++)
		{
			int[] currentGroup = ascriptives.get(i);
			ArrayList<ArrayList<Integer>> currentGroupList = new ArrayList<ArrayList<Integer>>();
			for (int j = 0; j < currentGroup.length; j++)
			{
				ArrayList<Integer> currentAsc = new ArrayList<Integer>(); 
				currentAsc.add(currentGroup[j]);
				currentGroupList.add(currentAsc);
			}
			
			ret.add(currentGroupList);
		}
		
		for (int i = 0; i < referenceList.size(); i++)
		{
			TaggedList currentRefCat = referenceList.get(i);
			ArrayList<Integer> refGroup = new ArrayList<Integer>();
			
			for (int j = 0; j < ascriptives.size(); j++)
			{
				int[] currentGroup = ascriptives.get(j);
				
				// register what is represented
				if (!refGroup.contains(currentGroup[i]))
					refGroup.add(currentGroup[i]);	
			}
			
			// use complement if complement is smaller.
			int compSize = currentRefCat.size() - refGroup.size();
			ArrayList<Integer> compSet = new ArrayList<Integer>();
			boolean complementUsed = false;
			boolean allUsed = false;
			if (compSize == 0)
				allUsed = true;
			if ((compSize < refGroup.size()) && (compSize != 0))
			{
				complementUsed = true;
				// create compset
				for (int j = 0; j < currentRefCat.size(); j++)
				{
					if (!refGroup.contains(j))
						compSet.add(findCompVersion(j));
				}
			}
			
			// create new groups and use complement if needed
			for (int j = 0; j < ret.size(); j++)
			{
				ArrayList<ArrayList<Integer>> currentAscCopyGroup = ret.get(j);
				if (complementUsed)
				{
					currentAscCopyGroup.set(i, compSet);
				}
			}
		}

		System.out.println("THIS IS THE NEW FORM:");
		printCoalition(ret);
		
		if (hasZeros(ret))
			System.out.println("DUDE, THIS THING HAS ZEROS?  WTF!!!!???");
		else
			System.out.println("THIS METHOD OK!");
		return ret;
	}
	*/
	
	

	// returns -10 if in is 0, -11 if in is 1, etc.  Used for complement representation
	private static int findCompVersion(int in)
	{
		return (in + 10) * -1;
	}

	// returns 0 if -10, 1 if -11, etc.  Used for reverting back to normal representation
	private static int findNormVersion(int in)
	{
		return (in * -1) -10;
	}

	/*
	 * Returns an int[] indicating which groups need to be removed due to zero population.  So, if the 
	 * result is [1, 3, 5], groups 1, 3, and 5 from ascriptives need to be removed. 
	 */
	/*
	private static int[] zeroCheck(List<int[]> ascriptives, ArrayList2D referenceList, PopulationInterface pop)
	{
		ArrayList<int[]> ret = new ArrayList<int[]>();



		return ret;
	}
	 */

	// Returns a List<int[]> w/ all duplicates of input removed
	private static ArrayList<ArrayList<ArrayList<Integer>>> removeDuplicates(ArrayList<ArrayList<ArrayList<Integer>>> inputList)
	{
		ArrayList<ArrayList<ArrayList<Integer>>> ret = new ArrayList<ArrayList<ArrayList<Integer>>>();

		// loop through the list
		for (int i = 0; i < inputList.size(); i++)
		{
			// for each member in the list, loop through and check if any
			// other member matches
			if (!contains(ret, inputList.get(i)))
				ret.add(inputList.get(i));
		}

		return ret;
	}

	private static boolean contains(ArrayList<ArrayList<ArrayList<Integer>>> inputArray, ArrayList<ArrayList<Integer>> member)
	{
		for (int i = 0; i < inputArray.size(); i++)
		{
			boolean found = true;
			ArrayList<ArrayList<Integer>> currentGroup = inputArray.get(i);
			for (int j = 0; j < currentGroup.size(); j++)
			{
				ArrayList<Integer> currentAscList = currentGroup.get(j);
				ArrayList<Integer> memberAscList = member.get(j);
				if (currentAscList.size() != memberAscList.size())
					found = false;
				else
				{
					for (int k = 0; k < currentAscList.size(); k++)
					{
						if (currentAscList.get(k).intValue() != memberAscList.get(k).intValue())
							found = false;
					}
				}
			}
			if (found)
				return true;
		}
		return false;
	}

	// returns true if the list cotains a member (ArrayList<Integer>) w/ zero size... which should
	// actually never happen!
	private static boolean hasZeros(ArrayList<ArrayList<ArrayList<Integer>>> list)
	{
		boolean ret = false;

		for (int i = 0; i < list.size(); i++)
		{
			for (int j = 0; j < list.get(i).size(); j++)
			{
				if (list.get(i).get(j).size() == 0)
					ret = true;
			}
		}

		return ret;
	}
	
	private static void printCoalition(ArrayList<ArrayList<ArrayList<Integer>>> inputArray)
	{
		for (int i = 0; i < inputArray.size(); i++)
		{
			System.out.println("Group " + i);
			ArrayList<ArrayList<Integer>> group = inputArray.get(i);
			System.out.print("{");
			for (int j = 0; j < group.size(); j++)
			{
				ArrayList<Integer> member = group.get(j);
				System.out.print(" {");
				for (int k = 0; k < member.size(); k++)
				{
					System.out.print(" " + member.get(k));
				}
				System.out.print("} ");
			}
			System.out.print("}");
			System.out.println(" ");
		}
	}
	
	private static void printAscriptiveList(List<int[]> input)
	{
		for (int i = 0; i < input.size(); i++)
		{
			String arrayString = "{";
			int[] a = input.get(i);
			for (int j = 0; j < a.length-1; j++)
			{
				arrayString += a[j] + ", ";
			}
			arrayString += a[a.length-1] + "}";
			System.out.println(arrayString);
		}
	}
}
